<?php

namespace App\Http\Utils\Integral;

use Illuminate\Support\Facades\DB;

/**
 * Class Task
 * @package App\Http\Utils\Integral
 */
class Tasks
{
    /**
     * 规则
     * @var Roles
     */
    private $roles;

    /**
     * 订单
     * @var Order
     */
    public $order;

    /**
     * 今天
     * @var array
     */
    private $today;

    /**
     * Task constructor.
     * @param Roles $roles
     * @param Order $order
     */
    public function __construct(Roles $roles, Order $order)
    {
        $this->roles = $roles;
        $this->order = $order;
        $this->today = [strtotime(date('Y-m-d 00:00:00', Time::current())), Time::current()];
        $this->luckGrant();
        $this->singleGrant();
        $this->cumulativeGrant();
    }

    /**
     * 关闭当天的天天红包发放
     */
    private function closeDayTask()
    {
        if ($this->roles->closeDayGrant) {
            DB::table('task')
                ->where([
                    'type'    => 'day',
                    'user_id' => $this->order->user->userId,
                    'disable' => 'true',
                    'enabled' => 'true',
                ])->where('count', '>=', 0)
                ->get()
                ->map(function ($task) {
                    $role = json_decode($task->pistolgraph);
                    if ($task->grant_integral + $role->day_every > $role->day_return) {
                        $need = $role->day_return - $task->grant_integral;
                    } else {
                        $need = $role->day_every;
                    }
                    DB::table('task')->where(['id' => $task->id,])->update([
                        'count'             => $task->count - $need,
                        'grant_integral'    => $task->grant_integral + $need,
                        'unissued_integral' => $task->unissued_integral + $need,
                        'disable'           => 'false',//天天红包未实际发放
                        'update_time'       => Time::current(),
                    ]);
                });
        }
    }

    /**
     * 幸运红包结算
     */
    private function luckGrant()
    {
        // TODO 消费开启
        $this->closeDayTask();
        if ($this->order->shop->luck_enabled) {
            $hasGrant = 0;
            DB::table('task')
                ->where([
                    'type'    => 'luck',
                    'disable' => 'true',
                    'enabled' => 'true',
                ])->whereBetween('create_time', $this->today)
                ->whereIn('pistolgraph->id', $this->roles->luckRoles->pluck('id'))
                ->lockForUpdate()
                ->get()
                ->map(function ($value) use (&$hasGrant) {
                    $value->pistolgraph = json_decode($value->pistolgraph);
                    // 触发当前规则的用户
                    $user = $this->order->user($value->user_id, $this->order->shop->shopId);
                    if (!$user->luck_enabled) {
                        return;
                    }
                    // 当前用户应该发放的积分
                    $grant = $this->order->integral * $value->pistolgraph->luck_ratio / 100;
                    if ($this->order->integral < $hasGrant + $grant) {//该笔订单积分是否发放完
                        $user->flow($this->order->orderNum, 'fail', '该笔订单产生的积分已发放完', '幸运积分红包', 0, $value->id);
                        return;
                    }
                    if ($this->order->shop->totalAmount < $grant) {//商户积分池的积分是否发放完
                        $user->flow($this->order->orderNum, 'fail', '商户积分池的积分已发放完', '幸运积分红包', 0, $value->id);
                        return;
                    }
                    // 发放积分给触发规则用户
                    $user->flow($this->order->orderNum, 'success', 'success', '幸运积分红包', $grant, $value->id);
                    // 扣除商户对应的积分
                    $this->order->shop
                        ->flow($this->order->orderNum, $user->userId, -$grant, '幸运积分红包', $value->id);
                    // 修改当前积分任务的发放次数和发放金额，当次数为0 关闭改幸运规则
                    if ($value->count > 1) {
                        DB::table('task')
                            ->where(['id' => $value->id,])
                            ->update([
                                'count'          => $value->count - 1,
                                'grant_integral' => $value->grant_integral + $grant,
                                'update_time'    => Time::current(),
                            ]);
                    } else {
                        DB::table('task')
                            ->where(['id' => $value->id,])
                            ->update([
                                'count'          => 0,
                                'grant_integral' => $value->grant_integral + $grant,
                                'update_time'    => Time::current(),
                                'disable'        => 'false',
                            ]);
                    }
                    $hasGrant = $hasGrant + $grant;
                });
        }
        $this->luckJoin();
    }

    /**
     * TODO 消费开启
     * 加入能触发规则
     */
    private function luckJoin()
    {
        foreach ($this->roles->luckRoles as $luckRole) {
            if (count(array_intersect($this->order->popularize, json_decode($luckRole->luck_popularize))) > 0
                || count(array_intersect($this->order->distribution, json_decode($luckRole->luck_distribution))) > 0) {
                $disableLuck = DB::table('task')
                    ->where([
                        'pistolgraph->id' => $luckRole->id,
                        'user_id'         => $this->order->user->userId,
                        'type'            => 'luck',
                    ])->whereBetween('create_time', $this->today)
                    ->first();
                if (is_null($disableLuck)) {
                    $this->task($luckRole, 'luck', 0, 0, $luckRole->luck_count, 'true');
                }
            }
        }
    }

    private $userIds;

    /**
     * @param string $userId
     * @return array
     */
    private function userId($userId)
    {
        if (is_null($this->userIds)) {
            if (is_numeric($userId)) {
                $this->userIds = DB::table(env('DB_DATABASE_USER', '') . 'user as user')
                    ->select('id as user_id')
                    ->where('id', $userId)
                    ->union(function ($query) use ($userId) {
                        $query->select(DB::raw("CONCAT('v',id) as user_id"))
                            ->from(env('DB_DATABASE_USER', '') . 'wx_user as v_user')
                            ->where('user_id', $userId);
                    })->union(function ($query) use ($userId) {
                        $query->select(DB::raw("CONCAT('a',id) as user_id"))
                            ->from(env('DB_DATABASE_USER', '') . 'alipay_user as a_user')
                            ->where('user_id', $userId);
                    })->distinct()
                    ->pluck('user_id')
                    ->toArray();
            } else {
                $this->userIds = explode(',', $userId);
            }
        }
        return $this->userIds;
    }

    /**
     * 单次消费
     */
    private function singleGrant()
    {
        // 消费次数
        $count = DB::table('orders')
            ->whereIn('user_id', $this->userId($this->order->user->userId))
            ->where('shop_id', $this->order->shop->shopId)
            ->count('id');
        foreach ($this->roles->singleRoles as $singleRole) {
            if ($this->order->money() < $singleRole->day_satisfy) {
                continue;
            }
            if ($singleRole->day_target == 'old') {
                if ($count <= 0) continue;
            } elseif ($singleRole->day_target == 'new') {
                if ($count > 0) continue;
            }
            // 多次触发
            if ($singleRole->day_overly == 'true') {
                $times = floor($this->order->money() / $singleRole->day_satisfy);
            } else {
                $times = 1;
            }
            for ($i = 0; $i < $times; $i++) {
                if ($this->order->shop->day_enabled && $this->order->user->day_enabled) {
                    if ($this->roles->closeDayGrant) {
                        $this->task($singleRole, 'day', $singleRole->day_every, $singleRole->day_every, $singleRole->day_return - $singleRole->day_every, 'false');
                    } else {
                        if ($this->order->shop->totalAmount < $singleRole->day_every) {
                            $taskId = $this->task($singleRole, 'day', 0, 0, $singleRole->day_return, 'true');
                            $this->order->user
                                ->flow($this->order->orderNum, 'fail', '商户积分池的积分已发放完毕', '天天积分红包', 0, $taskId);
                        } else {
                            $taskId = $this->task($singleRole, 'day', $singleRole->day_every, 0, $singleRole->day_return - $singleRole->day_every, 'true');
                            $this->order->user
                                ->flow($this->order->orderNum, 'success', 'success', '天天积分红包', $singleRole->day_every, $taskId);
                            $this->order->shop
                                ->flow($this->order->orderNum, $this->order->user->userId, -$singleRole->day_every, '天天积分红包', $taskId);
                        }
                    }
                } else {
                    $this->task($singleRole, 'day', 0, 0, $singleRole->day_return, 'true');
                }
            }
        }
    }

    /**
     * 累计消费
     */
    private function cumulativeGrant()
    {
        $cumulative = DB::table('user')
                ->whereIn('user_id', $this->userId($this->order->user->userId))
                ->where('shop_id', $this->order->shop->shopId)
                ->sum('cumulative') + $this->order->money();
        /**
         * 取累计消费最高的那条规则
         */
        $role = null;
        foreach ($this->roles->cumulativeRoles as $cumulativeRole) {
            if ($cumulative >= $cumulativeRole->day_satisfy) {
                if (isset($role->day_satisfy)) {
                    if ($role->day_satisfy < $cumulativeRole->day_satisfy) {
                        $role = $cumulativeRole;
                    }
                } else {
                    $role = $cumulativeRole;
                }
            }
        }
        if (!is_null($role)) {
            // 多次触发
            if ($role->day_overly == 'true') {
                $times = floor($cumulative / $role->day_satisfy);
            } else {
                $times = 1;
            }
            for ($i = 0; $i < $times; $i++) {
                if ($this->order->shop->day_enabled && $this->order->user->day_enabled) {
                    if ($this->roles->closeDayGrant) {
                        $this->task($role, 'day', $role->day_every, $role->day_every, $role->day_return - $role->day_every, 'false');
                    } else {
                        if ($this->order->shop->totalAmount < $role->day_every) {
                            $taskId = $this->task($role, 'day', 0, 0, $role->day_return, 'true');
                            $this->order->user
                                ->flow($this->order->orderNum, 'fail', '商户积分池的积分已发放完毕', '天天积分红包', 0, $taskId);
                        } else {
                            $taskId = $this->task($role, 'day', $role->day_every, 0, $role->day_return - $role->day_every, 'true');
                            $this->order->user
                                ->flow($this->order->orderNum, 'success', 'success', '天天积分红包', $role->day_every, $taskId);
                            $this->order->shop
                                ->flow($this->order->orderNum, $this->order->user->userId, -$role->day_every, '天天积分红包', $taskId);
                        }
                    }
                } else {
                    $this->task($role, 'day', 0, 0, $role->day_return, 'true');
                }
            }
            $this->order->user->clearCumulative($this->userId($this->order->user->userId),
                $cumulative - $times * $role->day_satisfy);
        } else {
            $this->order->user->cumulative($this->order->money());
        }
    }

    /**
     * @param mixed $role 规则
     * @param string $type 规则类型
     * @param float $grantIntegral 已发放
     * @param float $unissuedIntegral 未实际发放
     * @param float $count 天天红包【待领取个数】幸运红包【待领取次数】
     * @param string $disable 天天红包【是否领取完毕】幸运红包【标记当天是否已实际发放】
     * @return int
     */
    private function task($role, $type, $grantIntegral, $unissuedIntegral, $count, $disable)
    {
        return DB::table('task')
            ->insertGetId([
                'enabled'           => 'true',
                'user_id'           => $this->order->user->userId,
                'order_num'         => $this->order->orderNum,
                'shop_id'           => $this->order->shop->shopId,
                'pistolgraph'       => json_encode($role),
                'type'              => $type,
                'grant_integral'    => $grantIntegral,
                'unissued_integral' => $unissuedIntegral,
                'count'             => $count,
                'disable'           => $disable,
                'create_time'       => Time::current(),
                'update_time'       => Time::current(),
            ]);
    }
}